﻿#region Copyright and License
/*==============================================================================
 *  Copyright (c) cndotnet.org Corporation.  All rights reserved.
 * ===============================================================================
 * This code and information is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the implied warranties
 * of merchantability and fitness for a particular purpose.
 * ===============================================================================
 * Licensed under the GNU General Public License (GPL) v2
 * http://www.cndotnet.org/ezsocio
 * ==============================================================================*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace DependenceInjection.Unity
{
    /// <summary>
    /// The specific container context for Unity
    /// </summary>
    public class UnityContainerContext : ContainerContextBase
    {
        #region Fields

        /// <summary>
        /// The lock used for synchronous
        /// </summary>
        private static readonly object _synlock = new object();

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="UnityContainerContext"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        public UnityContainerContext(string name)
            : base(name)
        {
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the current context.
        /// </summary>
        /// <value>The current context.</value>
        private HttpContext CurrentContext
        {
            get
            {
                HttpContext context = HttpContext.Current;
                if (context == null)
                {
                    throw new Exception("The current httpcontext is null");
                }
                return context;
            }
        }

        #endregion

        #region Override Methods

        /// <summary>
        /// Initializes container.
        /// </summary>
        public override void Initialize()
        {
            OnBeforeInitialized(new ContainerEventArgs(this, ContainerType.Unity));

            if (CurrentContext.Application[Name] == null)
            {
                lock (_synlock)
                {
                    if (CurrentContext.Application[Name] == null)
                    {
                        IUnityContainer currentContainer = new UnityContainer();
                        UnityConfigurationSection section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
                        section.Containers[Name].Configure(currentContainer);
                        CurrentContext.Application[Name] = currentContainer;
                    }
                }
            }

            OnAfterInitialized(new ContainerEventArgs(this, ContainerType.Unity));
        }

        /// <summary>
        /// Resolves this instance.
        /// </summary>
        /// <typeparam name="T">Parameter type.</typeparam>
        /// <returns></returns>
        public override T Resolve<T>()
        {
            try
            {
                Initialize();

                IUnityContainer currentContainer = CurrentContext.Application[Name] as IUnityContainer;
                return currentContainer.Resolve<T>();
            }
            catch (Exception ex)
            {
                OnResolveFailed(new ContainerFailedEventArgs(this, ContainerType.Unity, ex));
                return default(T);
            }
        }

        /// <summary>
        /// Tears down.
        /// </summary>
        public override void TearDown()
        {
            OnBeforeTearDown(new ContainerEventArgs(this, ContainerType.Unity));

            CurrentContext.Application[Name] = null;

            OnAfterTearDown(new ContainerEventArgs(this, ContainerType.Unity));
        }

        #endregion

    }
}
